package com.sunshine.serialport.tools.query;


import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @classDescription:搜索过滤工具类
 * @author:xiayingjie
 * @createTime:13-10-22 上午10:23
 */
public class SpecificationUtil<T> {

    /**
     * 根据List获取查询对象
     *
     * @param filters
     * @param entityClazz
     * @param <T>
     * @return
     */
    public static <T> Specification<T> bySearchFilter(final List<PropertyFilter> filters, final Class<T> entityClazz) {
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                if (null != filters && !filters.isEmpty()) {

                    List<Predicate> predicates = new ArrayList<>();


                    for (PropertyFilter pf : filters) {
                        Path path;
                        if (pf.getPropertyName().indexOf("_") > -1) {
                            String[] names = pf.getPropertyName().split("_");
                            path = root.get(names[0]).get(names[1]);
                        } else {
                            path = root.get(pf.getPropertyName());
                        }
                        if (null == pf.getPropertyValue()) {
                            continue;
                        }
                        Object value = pf.getPropertyValue();

                        if (pf.getPropertyType().equals(Date.class)) {
                            value = new Date(pf.getPropertyValue().toString());
                        }

                        if (pf.getPropertyType().equals(Boolean.class)) {
                            value = new Boolean(pf.getPropertyValue().toString());
                        }


                        switch (pf.getMatchType()) {
                            case EQ:
                                predicates.add(cb.equal(path, value));
                                break;
                            case LIKE:
                                predicates.add(cb.like(path, "%" + value + "%"));
                                break;
                            case LT:
                                predicates.add(cb.lessThan(path, (Comparable) value));
                                break;
                            case GT:
                                predicates.add(cb.greaterThan(path, (Comparable) value));
                                break;
                            case LE:
                                predicates.add(cb.lessThanOrEqualTo(path, (Comparable) value));
                                break;
                            case GE:
                                predicates.add(cb.greaterThanOrEqualTo(path, (Comparable) value));
                                break;
                            case IN:
                                predicates.add(path.in(String.valueOf(value).split(",")));
                                break;
                            case NQ:
                                predicates.add(cb.notEqual(path, (Comparable) value));
                                break;
                            case NIN:
                                predicates.add(cb.not(path.in(String.valueOf(value).split(","))));
                                break;
                        }


                    }

                    //去重
                    //query.select(root.get("id")).distinct(true);

                    if (predicates.size() > 0) {
                        return cb.and(predicates.toArray(new Predicate[predicates.size()]));
                    }


//                       for( Predicate predicate:predicates){
//                           query.where(predicate);
//                       }

                }

                return cb.conjunction();

            }
        };
    }

    /**
     * 根据List获取查询对象
     *
     * @param filters
     * @param entityClazz
     * @param <T>
     * @return
     */
    public static <T> Specification<T> bySearchFilter(final List<PropertyFilter> filters, final Class<T> entityClazz, String joinName, final List<PropertyFilter> joinFilters) {
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> allPredicates = new ArrayList<>();
                if (null != joinFilters && !joinFilters.isEmpty()) {
                    Join join = root.join(joinName);
                    allPredicates.addAll(getPredicateList(joinFilters, join, cb));
                    query.select(root.get("id")).distinct(true);
                }

                if (null != filters && !filters.isEmpty()) {

                    allPredicates.addAll(getPredicateList(filters, root, cb));
                }
                if (allPredicates.size() > 0) {
                    return cb.and(allPredicates.toArray(new Predicate[allPredicates.size()]));
                }
                return cb.conjunction();
            }
        };
    }


    public static List<Predicate> getPredicateList(final List<PropertyFilter> filters, Path root, CriteriaBuilder cb) {
        List<Predicate> predicates = new ArrayList<>();


        for (PropertyFilter pf : filters) {
            Path path;
            if (pf.getPropertyName().indexOf("_") > -1) {
                String[] names = pf.getPropertyName().split("_");
                path = root.get(names[0]).get(names[1]);
            } else {
                path = root.get(pf.getPropertyName());
            }
            if (null == pf.getPropertyValue()) {
                continue;
            }
            Object value = pf.getPropertyValue();

            if (pf.getPropertyType().equals(Date.class)) {
                value = new Date(pf.getPropertyValue().toString());
            }

            if (pf.getPropertyType().equals(Boolean.class)) {
                value = new Boolean(pf.getPropertyValue().toString());
            }


            switch (pf.getMatchType()) {
                case EQ:
                    predicates.add(cb.equal(path, value));
                    break;
                case LIKE:
                    predicates.add(cb.like(path, "%" + value + "%"));
                    break;
                case LT:
                    predicates.add(cb.lessThan(path, (Comparable) value));
                    break;
                case GT:
                    predicates.add(cb.greaterThan(path, (Comparable) value));
                    break;
                case LE:
                    predicates.add(cb.lessThanOrEqualTo(path, (Comparable) value));
                    break;
                case GE:
                    predicates.add(cb.greaterThanOrEqualTo(path, (Comparable) value));
                    break;
                case IN:
                    predicates.add(path.in(String.valueOf(value).split(",")));
                    break;
                case NQ:
                    predicates.add(cb.notEqual(path, (Comparable) value));
                    break;
                case NIN:
                    predicates.add(cb.not(path.in(String.valueOf(value).split(","))));
                    break;
            }

        }
        return predicates;
    }



//        //两张表关联查询
//        Join<Article,User> userJoin = root.join(root.getModel().getSingularAttribute("user",User.class),JoinType.LEFT);
//        predicate.add(cb.like(userJoin.get("nickname").as(String.class), "%" + searchArticle.getNickname() + "%"));


    /**
     * 根据map获取查询对象
     * @param map
     * @param entityClazz
     * @param <T>
     * @return
     */
    public static <T> Specification<T> bySearchFilter(Map<String ,String> map, final Class<T> entityClazz , String joinName, Map<String ,String> joinMap ) {
        PropertyFilter pf=new PropertyFilter();
        for(String key:map.keySet()){
            if(!StringUtils.isBlank(map.get(key))){
               pf.addFilter(StringUtils.substringAfter(key,"_"),map.get(key));
            }
        }
        PropertyFilter pfFilter=new PropertyFilter();
        for(String key:joinMap.keySet()){
            if(!StringUtils.isBlank(joinMap.get(key))){
                pfFilter.addFilter(StringUtils.substringAfter(key,"_"),joinMap.get(key));
            }
        }
        return  bySearchFilter(pf.getFilterList(),entityClazz,joinName,pfFilter.getFilterList());
    }

    /**
     * 根据map获取查询对象
     * @param map
     * @param entityClazz
     * @param <T>
     * @return
     */
    public static <T> Specification<T> bySearchFilter(Map<String ,String> map, final Class<T> entityClazz) {
        PropertyFilter pf=new PropertyFilter();
        for(String key:map.keySet()){
            if(!StringUtils.isBlank(map.get(key))){
                pf.addFilter(StringUtils.substringAfter(key,"_"),map.get(key));
            }
        }
        return  bySearchFilter(pf.getFilterList(),entityClazz);
    }

    /**
     * 获取分页对象
     * @param queryDTO
     * @return
     */
    public static PageRequest getPageRequest(QueryDTO queryDTO){
         Sort sort=null;
         if(!StringUtils.isBlank(queryDTO.getOrder())){
             Sort.Order order;
             if(StringUtils.startsWith(queryDTO.getOrder(),"-")){
                 order=new Sort.Order(Sort.Direction.DESC,StringUtils.substringAfter(queryDTO.getOrder(),"-"));

             }else{
                 order=new Sort.Order(Sort.Direction.ASC, queryDTO.getOrder());
             }
             sort=Sort.by(order);
         }
         return  PageRequest.of(queryDTO.getPage(),queryDTO.getSize(),sort);
    }
}
